{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example: combining MOD file ion channels with rxd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A version of this notebook may be run online via Google Colab at https://tinyurl.com/neuron-rxd-and-mod\n", " (make a copy or open in playground mode)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NEURON's reaction-diffusion infrastructure can be used to readily allow intracellular concentrations to respond to currents generated in MOD files, as long as:\n", "\n", "- `nrn_region='i'` is specified for the `rxd.Region` (so that it knows it corresponds to the electrophysiology region of the inside of the cell), AND\n", "the name and charge of the ion/etc are given in the `rxd.Species` declaration.\n", "Satisfying the above two rules also allows MOD files to see intracellular concentrations.\n", "\n", "- 3D extracellular concentrations also interoperate with electrophysiology automatically as long as name and charge are specified.\n", "\n", "As a simple example, we consider a model with just a single point soma, of length and diameter 10 microns, with Hodgkin-Huxley kinetics (which uses the built in mod file `hh.mod`), and dynamic sodium (declared using rxd but without any additional kinetics)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup NEURON library and imports" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's import our usual NEURON libraries and definitions. Remember you can use either `um` or `µm` for micron." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:32.533220Z", "iopub.status.busy": "2025-08-18T03:36:32.533068Z", "iopub.status.idle": "2025-08-18T03:36:32.942835Z", "shell.execute_reply": "2025-08-18T03:36:32.942411Z" } }, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from neuron import n, rxd\n", "from neuron.units import mV, ms, um, mM\n", "\n", "## needed for standard run system\n", "n.load_file(\"stdrun.hoc\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now import `plotly`, a graphics library. (You could easily modify this code to use other graphics libraries like `matplotlib`, `plotnine`, or `bokeh`.)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.000047Z", "iopub.status.busy": "2025-08-18T03:36:32.999808Z", "iopub.status.idle": "2025-08-18T03:36:33.073147Z", "shell.execute_reply": "2025-08-18T03:36:33.072757Z" } }, "outputs": [], "source": [ "import plotly.graph_objects as go\n", "from plotly.subplots import make_subplots" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup the model" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.075727Z", "iopub.status.busy": "2025-08-18T03:36:33.075114Z", "iopub.status.idle": "2025-08-18T03:36:33.100620Z", "shell.execute_reply": "2025-08-18T03:36:33.100253Z" } }, "outputs": [], "source": [ "## define morphology\n", "soma = n.Section(name=\"soma\")\n", "soma.L = soma.diam = 10 * um\n", "\n", "## add ion channels (n.hh is built in, so always available)\n", "n.hh.insert(soma)\n", "\n", "## define cytosol. MUST specify nrn_region for concentrations to update\n", "cyt = rxd.Region([soma], name=\"cyt\", nrn_region=\"i\")\n", "\n", "## define sodium. MUST specify name and charge for concentrations to update\n", "na = rxd.Species(cyt, name=\"na\", charge=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we could have written `n.hh.insert(soma.wholetree())` to put Hodgkin-Huxley channels everywhere in the cell that the soma is part of, but since there is only one section, this is not required." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also add an excitatory synapse to receive events (these will trigger the cell to spike)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.102996Z", "iopub.status.busy": "2025-08-18T03:36:33.102370Z", "iopub.status.idle": "2025-08-18T03:36:33.105268Z", "shell.execute_reply": "2025-08-18T03:36:33.104986Z" } }, "outputs": [], "source": [ "syn = n.ExpSyn(soma(0.5))\n", "syn.tau = 1 * ms\n", "syn.e = 0 * mV" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Add a stimulus" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The spike events themselves (two events, 15 ms apart starting at n.t=10*ms):" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.107007Z", "iopub.status.busy": "2025-08-18T03:36:33.106857Z", "iopub.status.idle": "2025-08-18T03:36:33.109719Z", "shell.execute_reply": "2025-08-18T03:36:33.109401Z" } }, "outputs": [], "source": [ "stim = n.NetStim()\n", "stim.interval = 15 * ms\n", "stim.number = 2\n", "stim.start = 10 * ms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Send those events to our synapse:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.111873Z", "iopub.status.busy": "2025-08-18T03:36:33.111278Z", "iopub.status.idle": "2025-08-18T03:36:33.114068Z", "shell.execute_reply": "2025-08-18T03:36:33.113750Z" } }, "outputs": [], "source": [ "nc = n.NetCon(stim, syn)\n", "nc.weight[0] = 0.001" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup recording variables" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.115608Z", "iopub.status.busy": "2025-08-18T03:36:33.115470Z", "iopub.status.idle": "2025-08-18T03:36:33.118641Z", "shell.execute_reply": "2025-08-18T03:36:33.118302Z" } }, "outputs": [], "source": [ "t = n.Vector().record(n._ref_t)\n", "v = n.Vector().record(soma(0.5)._ref_v)\n", "na_vec = n.Vector().record(soma(0.5)._ref_nai)\n", "ina = n.Vector().record(soma(0.5)._ref_ina)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialize and run the simulation" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.120757Z", "iopub.status.busy": "2025-08-18T03:36:33.120164Z", "iopub.status.idle": "2025-08-18T03:36:33.131900Z", "shell.execute_reply": "2025-08-18T03:36:33.131593Z" } }, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n.finitialize(-65 * mV)\n", "n.continuerun(50 * ms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot it" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:33.133599Z", "iopub.status.busy": "2025-08-18T03:36:33.133460Z", "iopub.status.idle": "2025-08-18T03:36:33.520968Z", "shell.execute_reply": "2025-08-18T03:36:33.520566Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "